/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package pl.cezary.butler.walili.server;

import java.util.Collection;
import java.util.Comparator;
import java.util.Set;
import java.util.concurrent.*;
import java.util.logging.Level;
import java.util.logging.Logger;
import pl.cezary.butler.walili.common.IServerFacadeRemote;
import pl.cezary.butler.walili.common.Task;
import pl.cezary.butler.walili.common.TaskStatus;
import pl.cezary.butler.walili.server.shuffling.GapIdGenerator;
import pl.cezary.butler.walili.server.shuffling.TaskShufflingComparator;

/**
 *
 * @author Cezary Butler
 */
public abstract class AbstractServerFacade extends Queues implements IServerFacade, IServerFacadeRemote {

    protected static final Logger log = Logger.getLogger(AbstractServerFacade.class.getName());
    //private Set<ZadanieSerwer> zadania_w_toku = new ConcurrentSkipListSet<ZadanieSerwer>(TaskPriorityComparator.getInstance());
    protected final LinkedBlockingQueue<UserTask> pobraneZadania = new LinkedBlockingQueue<UserTask>();
    protected TaskSet zadaniaWKolejce = new TaskSet();
    protected Set<Task> zadania_w_toku = new TaskSet();
    protected final Comparator<Task> shufflingComparator = new SpecificationComparator<Task>(TaskPriorityComparator.getInstance(), new TaskShufflingComparator(new GapIdGenerator(1024)));
    protected final PriorityBlockingQueue<ServerTask> kolejkaZadan = new PriorityBlockingQueue<ServerTask>(Short.MAX_VALUE, shufflingComparator);
    protected final LinkedBlockingQueue<UserTask> wykonaneZadania = new LinkedBlockingQueue<UserTask>();
    protected final BlockingQueue<DelayedServerTask> zadaniaDoPrzywrocenia = new DelayQueue<DelayedServerTask>();

    public AbstractServerFacade() {
    }

    @Override
    TaskSet getTaskStorage() {
        return zadaniaWKolejce;
    }

    @Override
    public Task getTask() {
        try {
            Task zad = kolejkaZadan.poll(100, TimeUnit.MILLISECONDS);
            if (zad != null) {
                assert (zad.getStatus().czyPrzejscieDozwolone(TaskStatus.PRZETWARZANE));
                zad.setStatus(TaskStatus.PRZETWARZANE);
                zadania_w_toku.add(zad);
            }
            return zad;
        } catch (InterruptedException ex) {
            log.info("Przerwano pobieranie zadania");
            return null;
        }
    }

    @Override
    public void logout() {
        log.log(Level.WARNING, "Proba wykonania niedozwolonej operacji", new Exception());
        throw new UnsupportedOperationException("Wylogowanie jest dostepne tylko z fasady u\u017cytkownika");
    }

    @Override
    public void registerTaskSent(UserId user, Task zadanie) {
        ServerTask zad = new ServerTask(zadanie);
        getFetchedTasksToRegisterQueue().offer(new UserTask(user, ServerTask.getZadanieSerwer(zad)));
    }

    @Override
    public void registerTaskDone(UserId user, Task zadanie) {
        getDoneTaskToRegisterQueue().offer(new UserTask(user, ServerTask.getZadanieSerwer(zadanie)));
    }
    
    public void zarejestrujWykonanieZadan(UserId user, Collection<? extends Task> zadanie) {
        for(Task task: zadanie)
            getDoneTaskToRegisterQueue().offer(new UserTask(user, ServerTask.getZadanieSerwer(task)));
    }

    @Override
    public BlockingQueue<UserTask> getDoneTaskToRegisterQueue() {
        return wykonaneZadania;
    }

    @Override
    public BlockingQueue<UserTask> getFetchedTasksToRegisterQueue() {
        return pobraneZadania;
    }

    @Override
    public BlockingQueue<DelayedServerTask> getTasksToRevalidateQueue() {
        return zadaniaDoPrzywrocenia;
    }

    @Override
    void reprocess(Task zadanie) {
        if (!getTaskStorage().contains(zadanie)) {
            ServerTask zad = ServerTask.getZadanieSerwer(zadanie);
            getTaskStorage().add(zad);
            kolejkaZadan.offer(zad);
        }
    }

    @Override
    public void taskDone(Task zad) {
        throw new UnsupportedOperationException("Not supported ever.");
    }
}
